from fastapi import FastAPI, Depends, HTTPException, status
from fastapi.middleware.cors import CORSMiddleware
from sqlalchemy.orm import Session
from typing import List

from app import crud, models, schemas, qiniu_manager
from app.database import SessionLocal, engine, get_db
from app.recipe_parser import parse_recipe_text

# This is useful for development, but for production applications,
# you should use a database migration tool like Alembic.
models.Base.metadata.create_all(bind=engine)

app = FastAPI()

# CORS middleware setup
origins = [
    "http://localhost",
    "http://localhost:3000", # Default for create-react-app
    # Add other origins if needed
]

app.add_middleware(
    CORSMiddleware,
    allow_origins=origins,
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

@app.get("/api/v1/storage/upload-token", response_model=schemas.TokenResponse)
def api_get_upload_token():
    """
    Provides an upload token for the client to upload images to Qiniu.
    """
    token_data = qiniu_manager.get_upload_token()
    if not token_data or "token" not in token_data:
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail="Could not generate upload token. Check server configuration."
        )
    return token_data

@app.post("/api/v1/parse-recipe", response_model=schemas.ParseResponse)
def api_parse_recipe(request: schemas.ParseRequest):
    """
    Receives recipe text and returns a structured JSON representation.
    """
    parsed_data = parse_recipe_text(request.text)
    if "error" in parsed_data:
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=parsed_data["details"]
        )
    return parsed_data

@app.post("/api/v1/recipes", response_model=schemas.Recipe, status_code=status.HTTP_201_CREATED)
def api_create_recipe(recipe: schemas.RecipeCreate, db: Session = Depends(get_db)):
    """
    Saves a new recipe to the database.
    """
    return crud.create_recipe(db=db, recipe=recipe)

@app.get("/api/v1/recipes", response_model=List[schemas.Recipe])
def api_get_recipes(skip: int = 0, limit: int = 100, db: Session = Depends(get_db)):
    """
    Retrieves a list of all recipes from the database.
    """
    recipes = crud.get_recipes(db, skip=skip, limit=limit)
    return recipes

@app.get("/api/v1/recipes/{recipe_id}", response_model=schemas.Recipe)
def api_get_recipe(recipe_id: int, db: Session = Depends(get_db)):
    """
    Retrieves a single recipe by its ID.
    """
    db_recipe = crud.get_recipe_by_id(db, recipe_id=recipe_id)
    if db_recipe is None:
        raise HTTPException(status_code=404, detail="Recipe not found")
    return db_recipe

@app.delete("/api/v1/recipes/{recipe_id}", status_code=status.HTTP_204_NO_CONTENT)
def api_delete_recipe(recipe_id: int, db: Session = Depends(get_db)):
    """
    Deletes a recipe from the database.
    """
    success = crud.delete_recipe(db=db, recipe_id=recipe_id)
    if not success:
        raise HTTPException(status_code=404, detail="Recipe not found")
    return

@app.put("/api/v1/recipes/{recipe_id}", response_model=schemas.Recipe)
def api_update_recipe(recipe_id: int, recipe: schemas.RecipeUpdate, db: Session = Depends(get_db)):
    """
    Updates a recipe in the database.
    """
    db_recipe = crud.update_recipe(db=db, recipe_id=recipe_id, recipe_update=recipe)
    if db_recipe is None:
        raise HTTPException(status_code=404, detail="Recipe not found")
    return db_recipe
